package devcamp.team.connection;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Locale;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.StrictMode;
import android.util.Log;
import devcamp.team.data.WowoooooooUserData;

/**
 * サーバーと通信をするクラス
 * 
 * @author kkato
 *
 */
public class ServerConnectionModel {
    private static final String TAG = "ServerConnectionModel";
    private static final String KEY_USER_NAME = "username";
    private static final String KEY_TWITTER_ID = "twitterId";
    private static final String KEY_UNIQUE_ID = "id";
    private static final String KEY_LATITUDE = "latitude";
    private static final String KEY_LONGITUDE = "longitude";
    private static final String KEY_LOCATION_NAME = "location";
    private static final String KEY_REGISTRATION = "registration";
    private static final String KEY_USER_ARRAY = "user";
    
    // Google Geocoding API V3
    private static final String KEY_GEO_LATLNG = "latlng";
    private static final String KEY_GEO_SENSOR = "sensor";
    private static final String KEY_GEO_LANGUAGE = "language";
    private static final String KEY_GEO_STATUS = "status";
    private static final String KEY_GEO_RESULTS_ARRAY = "results";
    private static final String KEY_GEO_FORMATTED_ADDRESS = "formatted_address";
    private static final String KEY_GEO_TYPES = "types";
    private static final String KEY_GEO_TYPE_LEVEL4 = "sublocality_level_4";
    private static final String KEY_GEO_TYPE_LEVEL1 = "sublocality_level_1";

    /**
     * ユーザー登録を行う
     * 
     * @param userName  ユーザー名
     * @param twitterId TwitterID
     * @return ユニークID（このユニークIDが個人の識別になる=やほーする時の引数に使う） 登録に失敗した場合は-1
     */
    static public long registration(String userName, String twitterId) {
        if ((userName == null) || (twitterId == null)) {
            return -1;
        }

        String postStr = KEY_USER_NAME + "=" + userName + "&" +
                KEY_TWITTER_ID + "=" + twitterId;

        String data = sendToServer("http://www.devwowooooooo.appspot.com/registration", postStr);
        
        if (data == null) {
            return -1;
        }

        try {
            JSONObject rootObject = new JSONObject(data);
            boolean registrationObject = rootObject.getBoolean(KEY_REGISTRATION);
            
            if (registrationObject == false) {
                return -1;
            }
            
            long id = rootObject.getLong(KEY_UNIQUE_ID);
            return id;
        } catch (JSONException e) {
            e.printStackTrace();
            return -1;
        }
    }

    /**
     * やほー
     * 
     * @param uniqueId registrationメソッドの戻り値
     * @param latitude 緯度
     * @param longitude 経度
     * @param location 場所名
     * @return
     */
    static public boolean wowooooooo(long uniqueId, float latitude, float longitude, String location) {
        String postStr = KEY_UNIQUE_ID + "=" + uniqueId + "&" +
                KEY_LATITUDE + "=" + latitude + "&" +
                KEY_LONGITUDE + "=" + longitude + "&" +
                KEY_LOCATION_NAME + "=" + location;
        
        String data = sendToServer("http://www.devwowooooooo.appspot.com/yahooooooo", postStr);
        
        if (data == null) {
            return false;
        }

        try {
            JSONObject rootObject = new JSONObject(data);
            boolean registrationObject = rootObject.getBoolean(KEY_REGISTRATION);
            
            if (registrationObject == true) {
                return true;
            } else {
                return false;
            }
        } catch (JSONException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 近くのユーザー一覧を取得
     * 
     * @param latitude 緯度
     * @param longitude 経度
     * @return
     */
    static public ArrayList<WowoooooooUserData> getNearUsers(float latitude, float longitude) {
        String postStr = KEY_LATITUDE + "=" + latitude + "&" +
                KEY_LONGITUDE + "=" + longitude;
        
        String data = sendToServer("http://www.devwowooooooo.appspot.com/userlist", postStr);
        
        if (data == null) {
            return null;
        }

        try {
            JSONObject rootObject = new JSONObject(data);
            
            boolean registrationObject = rootObject.getBoolean(KEY_REGISTRATION);
            
            if (registrationObject == false) {
                return null;
            }
            
            JSONArray userArray = rootObject.getJSONArray(KEY_USER_ARRAY);
            
            if (userArray == null) {
                return null;
            }
            
            int count = userArray.length();
            JSONObject[] userObject = new JSONObject[count];
            for (int i = 0; i < count; i++) {
                userObject[i] = userArray.getJSONObject(i);
            }
            
            ArrayList<WowoooooooUserData> waoUserDataArray = new ArrayList<WowoooooooUserData>();
            for (JSONObject object : userObject) {
                WowoooooooUserData waoUserData = new WowoooooooUserData();
                waoUserData.setUserName(object.getString(KEY_USER_NAME));
                waoUserData.setTwitterId(object.getString(KEY_TWITTER_ID));
                waoUserData.setLatitude((float)object.getDouble(KEY_LATITUDE));
                waoUserData.setLongitude((float)object.getDouble(KEY_LONGITUDE));
                waoUserData.setLocationName(object.getString(KEY_LOCATION_NAME));
                waoUserDataArray.add(waoUserData);
            }
            
            return waoUserDataArray;
        } catch (JSONException e) {
            e.printStackTrace();
            return null;
        }
    }
    
    /**
     * 地名を取得
     * 
     * @param latitude 緯度
     * @param longitude 経度
     * @return
     */
    @SuppressWarnings("unused")
	static public String getLocationName(float latitude, float longitude) {
        String postStr = KEY_GEO_LATLNG + "=" + String.valueOf(latitude) + "," + 
        		String.valueOf(longitude) + "&" + 
        		KEY_GEO_SENSOR + "=false&" + 
        		KEY_GEO_LANGUAGE + "=" + Locale.getDefault().getLanguage();
        
        Log.d(TAG, "postStr : " + postStr);
        
        // POSTでは取得できなかったので、GETで取得する
        String data = sendToServerGet("http://maps.googleapis.com/maps/api/geocode/json" + "?" +  postStr);
        
        if (data == null) {
        	Log.d(TAG, "geo data null");
            return null;
        }
        
        String str = null;
        // JSON 解析
		try {
			JSONObject rootObject = new JSONObject(data);
			Log.d(TAG, "rootObject : " + rootObject.length());
			Log.d(TAG, "rootObject status : " + rootObject.getString(KEY_GEO_STATUS));
			
			if (rootObject.getString(KEY_GEO_STATUS).equals("OK")) {
				Log.d(TAG, "geo status OK!");
				JSONArray results = rootObject.getJSONArray(KEY_GEO_RESULTS_ARRAY);
				int k = results.length();
				for (int i = 0; i < k; i++) {
					JSONObject addr = (JSONObject) results.get(i);
					JSONArray types = addr.getJSONArray(KEY_GEO_TYPES);
					if (types.toString().indexOf(KEY_GEO_TYPE_LEVEL4) != -1) {
						// より詳細な住所からセットする
						str = addr.getString(KEY_GEO_FORMATTED_ADDRESS);
						break;
					} else if (types.toString().indexOf(KEY_GEO_TYPE_LEVEL1) != -1) {
						str = addr.getString(KEY_GEO_FORMATTED_ADDRESS);
						break;
					} else {
						// 上記詳細情報ない場合：比較的詳細な最初の情報からセット
						str = addr.getString(KEY_GEO_FORMATTED_ADDRESS);
						break;
					}
				}
				
			}
			
		} catch (JSONException e) {
			e.printStackTrace();
		}
		Log.d(TAG, "string : " + str);
        return str;
    }
    
    static private String sendToServer(String postUrl, String parameter) {
        // for debug
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build());

        String resultData = null;
        HttpURLConnection httpUrlConnection = null;
        InputStream inputStream = null;
        BufferedReader bufferedReader = null;
        
        try {
            URL url = new URL(postUrl);
            httpUrlConnection = (HttpURLConnection)url.openConnection();
            httpUrlConnection.setDoOutput(true);
            httpUrlConnection.setDoInput(true);
            httpUrlConnection.setRequestMethod("POST");
            httpUrlConnection.connect();

            OutputStream output = null;
            try {
                output = httpUrlConnection.getOutputStream();
                PrintStream printStream = new PrintStream(output);
                printStream.print(parameter);
                printStream.close();
            } finally {
                if (output != null) {
                    output.close();
                }
            }
            
            int statusCode = httpUrlConnection.getResponseCode();
            Log.d(TAG, "statusCode : " + statusCode);
            
            inputStream = httpUrlConnection.getInputStream();
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            
            StringBuilder stringBuilder = new StringBuilder();
            while (true) {
                String line = bufferedReader.readLine();
                if (line == null) {
                    break;
                }
                stringBuilder.append(line);
            }
            
            resultData = stringBuilder.toString();
        } catch(Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if(httpUrlConnection != null) {
                    httpUrlConnection.disconnect();
                }

                if (bufferedReader != null) {
                    bufferedReader.close();
                }
                
                if(inputStream != null) {
                    inputStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return resultData;
    }
    
    
    static private String sendToServerGet(String postUrl) {
        // for debug
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build());

        String resultData = null;
        HttpURLConnection httpUrlConnection = null;
        InputStream inputStream = null;
        BufferedReader bufferedReader = null;
        
        try {
            URL url = new URL(postUrl);
            httpUrlConnection = (HttpURLConnection)url.openConnection();
            httpUrlConnection.setDoInput(true);
            httpUrlConnection.setRequestMethod("GET");
            httpUrlConnection.connect();
            
            int statusCode = httpUrlConnection.getResponseCode();
            Log.d(TAG, "statusCode : " + statusCode);
            
            inputStream = httpUrlConnection.getInputStream();
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            
            StringBuilder stringBuilder = new StringBuilder();
            while (true) {
                String line = bufferedReader.readLine();
                if (line == null) {
                    break;
                }
                stringBuilder.append(line);
            }
            
            resultData = stringBuilder.toString();
        } catch(Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if(httpUrlConnection != null) {
                    httpUrlConnection.disconnect();
                }

                if (bufferedReader != null) {
                    bufferedReader.close();
                }
                
                if(inputStream != null) {
                    inputStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return resultData;
    }
}
